﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;

namespace FolderTag.Core
{
    /// <summary>
    /// 网络目录链接
    /// </summary>
    public class NetFolderConnection : IDisposable
    {
        [DllImport("mpr.dll")]
        private static extern int WNetAddConnection2(NetResource netResource,
        string password, string username, int flags);

        [DllImport("mpr.dll")]
        private static extern int WNetCancelConnection2(string name, int flags,
            bool force);

        [DllImport("mpr.dll")]
        private static extern int WNetOpenEnum(EResourceScope dwScope, EResourceType dwType, int dwUsage, NetResource lpNetResource, out IntPtr lphEnum);

        [DllImport("mpr.dll")]
        private static extern int WNetEnumResource(IntPtr lphEnum, ref long count, IntPtr buffer, ref int bufferSize);

        [DllImport("mpr.dll")]
        private static extern int WNetCloseEnum(IntPtr lphEnum);

        string _networkName;
        /// <summary>
        /// 获取局域网分享目录（注：需要提前自行添加Windows访问凭证，否者无法访问）
        /// </summary>
        /// <param name="path">例如：\\xxxxx </param>
        /// <returns></returns>
        public static List<NetResource> GetShareDictionary(string path)
        {
            List<NetResource> resultList = new List<NetResource>();
            //仅访问已被授权的目录
            NetResource lpNetResource = new NetResource()
            {
                RemoteName = path,
                Scope = EResourceScope.Remembered,
                DisplayType = EResourceDisplayType.Server,
                ResourceType = EResourceType.Any
            };
            IntPtr lphEnum = IntPtr.Zero;
            IntPtr ptrBuffer = IntPtr.Zero;
            int noRe = WNetOpenEnum(EResourceScope.GlobalNetwork, EResourceType.Any, 0, lpNetResource, out lphEnum);
            if (noRe == 0)
            {
                int buffer = 16384;//官方文档推荐
                ptrBuffer = Marshal.AllocHGlobal(buffer);//申请内存，不知道作用
                long count = -1;//不知道具体作用
                int nrRe = WNetEnumResource(lphEnum, ref count, ptrBuffer, ref buffer);
                if (nrRe == 0)
                {
                    long ptr = ptrBuffer.ToInt64();
                    NetResource nr = null;
                    while (true)
                    {
                        nr = Marshal.PtrToStructure<NetResource>(new IntPtr(ptr));
                        resultList.Add(nr);
                        ptr += Marshal.SizeOf(nr);
                        if (nr == null || string.IsNullOrEmpty(nr.RemoteName) || !Enum.IsDefined(typeof(EResourceScope), Marshal.ReadInt32(new IntPtr(ptr))))
                            break;
                    }
                }
            }
            Marshal.FreeHGlobal(ptrBuffer);
            if (lphEnum != IntPtr.Zero)
                WNetCloseEnum(lphEnum);

            return resultList;
        }

        /// <summary>
        /// 添加访问权限（未测试，勿使用）
        /// </summary>
        /// <param name="networkName"></param>
        /// <param name="credentials"></param>
        /// <exception cref="Win32Exception"></exception>
        public NetFolderConnection(string networkName, NetworkCredential credentials)
        {
            _networkName = networkName;

            var netResource = new NetResource
            {
                Scope = EResourceScope.GlobalNetwork,
                ResourceType = EResourceType.Disk,
                DisplayType = EResourceDisplayType.Share,
                RemoteName = networkName
            };

            var userName = string.IsNullOrEmpty(credentials.Domain)
                ? credentials.UserName
                : $@"{credentials.Domain}\{credentials.UserName}";

            var result = WNetAddConnection2(
                netResource,
                credentials.Password,
                userName,
                0);

            if (result != 0)
            {
                throw new Win32Exception(result, "Error connecting to remote share");
            }
        }

        ~NetFolderConnection()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            WNetCancelConnection2(_networkName, 0, true);
        }

    }

    [StructLayout(LayoutKind.Sequential)]
    public class NetResource
    {
        public EResourceScope Scope;
        public EResourceType ResourceType;
        public EResourceDisplayType DisplayType;
        public int Usage;
        public string LocalName;
        public string RemoteName;
        public string Comment;
        public string Provider;
    }
    public enum EResourceScope : int
    {
        /// <summary>
        /// 当前连接的资源
        /// </summary>
        Connected = 1,
        /// <summary>
        /// 网络资源
        /// </summary>
        GlobalNetwork,
        /// <summary>
        /// 已记住（持久）连接
        /// </summary>
        Remembered,
        Recent,
        Context
    };

    public enum EResourceType : int
    {
        /// <summary>
        /// 所有资源
        /// </summary>
        Any = 0,
        /// <summary>
        /// 磁盘资源
        /// </summary>
        Disk = 1,
        /// <summary>
        /// 打印资源
        /// </summary>
        Print = 2,
        Reserved = 8,
    }

    public enum EResourceDisplayType : int
    {
        Generic = 0x0,
        Domain = 0x01,
        Server = 0x02,
        Share = 0x03,
        File = 0x04,
        Group = 0x05,
        Network = 0x06,
        Root = 0x07,
        Shareadmin = 0x08,
        Directory = 0x09,
        Tree = 0x0a,
        Ndscontainer = 0x0b
    }
}
